﻿using System;
using System.Configuration;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Fuse8.ContentManagementFramework.BizFacade.Services.Contents.Queryable
{
    public class OrderByVisitor : ExpressionVisitor
    {
        readonly StringBuilder sb = new StringBuilder();
        public string GetSqlClause(Expression expression)
        {
            Visit(expression);

            return sb.ToString();
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            if (node.Expression.NodeType == ExpressionType.Constant)
            {
                var constExpression = (ConstantExpression)node.Expression;
                SetConstant(constExpression.Value, constExpression.Type, node.Member.Name);
                return node;
            }
            if (node.Expression.NodeType == ExpressionType.MemberAccess && ((MemberExpression)node.Expression).Expression.NodeType == ExpressionType.Constant)
            {
                var constExpression = (ConstantExpression)((MemberExpression)node.Expression).Expression;
                SetConstant(constExpression.Value, constExpression.Type, node.Member.Name);
                return node;
            }
            return base.VisitMember(node);
        }

        protected override Expression VisitConstant(ConstantExpression node)
        {
            SetConstant(node.Value, node.Type);
            
            return base.VisitConstant(node);
        }

        protected void SetConstant(object value, Type type, string name = null)
        {
            object val;
            if (string.IsNullOrEmpty(name))
            {
                val = value;
            }
            else
            {
                var info = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                if (info != null)
                {
                    val = info.GetValue(value);
                }
                else
                {
                    var propInfo = type.GetProperty(name);
                    if (propInfo != null)
                    {
                        val = propInfo.GetValue(value, null);
                    }
                    else
                    {
                        val = null;
                    }
                }
            }
            sb.Append(val);
        }

        protected override Expression VisitIndex(IndexExpression node)
        {
            sb.AppendFormat("it.[{0}]", node.Indexer.Name);
            return node;
        }

        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node.Method.Name=="get_Item")
            {
                sb.Append("it.[");
                Visit(node.Arguments[0]);
                sb.Append("]");
            }
            return node;
        }
    }
}